package com.night.icm.service.base.service;

import com.github.wenhao.jpa.PredicateBuilder;
import com.github.wenhao.jpa.Specifications;
import com.night.icm.common.exception.NoSuchDataException;
import com.night.icm.common.jpa.PageHelper;
import com.night.icm.common.service.PageDataUtil;
import com.night.icm.common.utils.PageDataDTO;
import com.night.icm.common.utils.SimpleDataDTO;
import com.night.icm.model.base.ProfessionDTO;
import com.night.icm.persistence.base.entity.Academy;
import com.night.icm.persistence.base.entity.Profession;
import com.night.icm.persistence.base.repository.AcademyRepository;
import com.night.icm.persistence.base.repository.ProfessionRepository;
import com.night.icm.persistence.business.entity.GraduationCreditRequirements;
import com.night.icm.persistence.business.reporsitory.GraduationCreditRequirementsRepository;
import com.night.icm.service.base.mapper.ProfseeionMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * ProfessionServiceImpl
 *
 * @author Liao ZhiYong
 * @date 2020/1/7
 */
@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class ProfessionServiceImpl implements ProfessionService {

    private final ProfessionRepository professionRepository;
    private final ProfseeionMapper profseeionMapper;
    private final AcademyRepository academyRepository;
    private final GraduationCreditRequirementsRepository graduationCreditRequirementsRepository;
    private final AcademyService academyService;

    @Autowired
    public ProfessionServiceImpl(ProfessionRepository professionRepository, ProfseeionMapper profseeionMapper, AcademyRepository academyRepository, GraduationCreditRequirementsRepository graduationCreditRequirementsRepository, AcademyService academyService) {
        this.professionRepository = professionRepository;
        this.profseeionMapper = profseeionMapper;
        this.academyRepository = academyRepository;
        this.graduationCreditRequirementsRepository = graduationCreditRequirementsRepository;
        this.academyService = academyService;
    }

    /**
     * 分页查询专业
     *
     * @param page      页号，从0开始
     * @param size      每页纪录条数
     * @param sort      排序字段, 例如：字段1,asc,字段2,desc
     * @param code      专业代码
     * @param name      专业名称
     * @param academyId 学院id
     * @return 专业信息
     */
    @Override
    public PageDataDTO<ProfessionDTO> findOnePage(int page, int size, String sort, String code, String name, String academyId) {
        PredicateBuilder<Profession> pb = Specifications.<Profession>and()
                .like(StringUtils.isNotBlank(code), "code", "%" + code + "%")
                .like(StringUtils.isNotBlank(name), "name", "%" + name + "%")
                .eq(StringUtils.isNotBlank(academyId), "academy.id", academyId);
        Page<Profession> entitys = this.professionRepository.findAll(pb.build(), PageHelper.generatePageRequest(page, size, sort));
        List<ProfessionDTO> professions = this.profseeionMapper.toList(entitys.getContent());
        return PageDataUtil.toPageData(entitys, professions);
    }

    /**
     * 新增专业
     *
     * @param professionDTO 专业信息
     * @return 新增专业信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProfessionDTO create(ProfessionDTO professionDTO) {
        // 设置所属学院
        Academy academy = this.getAcademyById(professionDTO.getAcademyId());
        // 设置专业毕业学分最低要求
        Profession profession = this.profseeionMapper.toEntity(professionDTO);
        profession.setAcademy(academy);
        // 保存专业毕业学分要求
        GraduationCreditRequirements graduationCreditRequirements = profession.getGraduationCreditRequirements();
        this.graduationCreditRequirementsRepository.save(graduationCreditRequirements);
        profession.setGraduationCreditRequirements(graduationCreditRequirements);
        // 保存专业
        Profession save = this.professionRepository.save(profession);
        return this.profseeionMapper.toDTO(save);
    }

    /**
     * 根据id获取学院
     *
     * @param id 学院id
     * @return 学院
     */
    public Academy getAcademyById(String id) {
        Optional<Academy> academy = this.academyRepository.findById(Long.valueOf(id));
        if (!academy.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return academy.get();
    }

    /**
     * 删除专业
     *
     * @param id 专业id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(String id) {
        this.professionRepository.deleteById(Long.valueOf(id));
    }

    /**
     * 更新专业信息
     *
     * @param id            专业id
     * @param professionDTO 专业信息
     * @return 更新后专业信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProfessionDTO update(String id, ProfessionDTO professionDTO) {
        Profession profession = this.getOne(id);
        this.profseeionMapper.updateEntity(professionDTO, profession);
        // 如果所属学院有变话，则修改所属学院
        if (!profession.getAcademy().getId().equals(Long.valueOf(professionDTO.getAcademyId()))) {
            Academy academy = this.getAcademyById(professionDTO.getAcademyId());
            profession.setAcademy(academy);
        }
        this.professionRepository.save(profession);
        return this.profseeionMapper.toDTO(profession);
    }

    /**
     * 根据id查找专业信息
     *
     * @param id 专业id
     * @param isGetClass 是否获取班级信息
     * @return 专业信息
     */
    @Override
    public ProfessionDTO findById(String id, Boolean isGetClass) {
        Profession profession = this.getOne(id);
        return isGetClass ? this.profseeionMapper.toDTO(profession) : this.profseeionMapper.toDtoByPage(profession);
    }

    /**
     * 根据id获取专业
     *
     * @param id 专业id
     * @return 专业
     */
    public Profession getOne(String id) {
        Optional<Profession> optionalProfession = this.professionRepository.findById(Long.valueOf(id));
        if (!optionalProfession.isPresent()) {
            throw new NoSuchDataException(id);
        }
        return optionalProfession.get();
    }

    /**
     * 查找所有专业信息
     *
     * @return 所有专业信息
     */
    @Override
    public List<ProfessionDTO> findAll() {
        List<Profession> all = this.professionRepository.findAll();
        return this.profseeionMapper.toList(all);
    }

    /**
     * 检查专业code是否已存在
     *
     * @param code 专业编号
     * @return 是否存在
     */
    @Override
    public SimpleDataDTO<Boolean> checkCodeExist(String code) {
        SimpleDataDTO<Boolean> simpleDataDTO = new SimpleDataDTO<>();
        Profession profession = this.professionRepository.findByCode(code);
        simpleDataDTO.setData(profession != null);
        return simpleDataDTO;
    }

    /**
     * 查找所有专业信息并排序
     *
     * @param param   排序参数
     * @param pattern 排序模式: asc/desc
     * @return 专业信息
     */
    @Override
    public List<ProfessionDTO> findAllBySort(String param, String pattern) {
        String keyType = "asc";
        Sort sort;
        if (keyType.equals(pattern)) {
            sort = new Sort(Sort.Direction.ASC, param);
        } else {
            sort = new Sort(Sort.Direction.DESC, param);
        }
        List<Profession> all = this.professionRepository.findAll(sort);
        return this.profseeionMapper.toList(all);
    }

    /**
     * 统计专业数量
     *
     * @return 统计专业数量
     */
    @Override
    public Long countProfession() {
        return this.professionRepository.count();
    }
}